/*
 *  mExercise.h
 *  Workout
 *
 *  Created by Matt Krugman on 4/27/09.
 *
 */


#ifndef _Exercise_H_
#define _Exercise_H_

#include <stdio.h>
#include <iostream>
#include <math.h>
#include "Time_ISO8601.h"

typedef enum HTMLLevel {
  HTMLP,
  HTMLH1,
  HTMLH2,
  HTMLH3,
  HTMLH4
};

typedef enum OutputType {
  OutputDebug,
  OutputHTML,
  OutputICAL
};

#define PI 3.14159265f
#define KG2LBS(x) x*2.20462262f
#define LBS2KG(x) x*0.45359237f


#define EXERCISES_MAX 50
#define EXERCISE_SETS_MAX 100
#define EXERCISE_SETS_WEIGHT 0
#define EXERCISE_SETS_REPS 1
#define EXERCISE_SETS_TIME 2
#define EXERCISE_SETS_ROUNDS 3

#define EXERCISE_BASE_PERCENT 0.6f

#define P_SNATCH 0.8f
#define P_BACKSQUAT 1.4f
#define P_BENCHPRESS 1.0f
#define P_CLEAN 1.0666f
#define P_CLEANANDJERK 1.0f
#define P_CLEANHIGHPULL 1.3f
#define P_CLEANPULL 1.3f
#define P_CLEANKNEES 0.95f
#define P_CLEANTWOPARTS 1.0f
#define P_CLEANTHREEPARTS 1.0f
#define P_COMBO 1.00f
#define P_COMBOA 1.00f
#define P_COMBOB 1.00f
#define P_COMBOC 1.0f
#define P_COMBOD 1.0f
#define P_COMBOE 1.0f
#define P_COMBOF 1.00f
#define P_COMBOG 1.0f
#define P_COMBOH 1.0f
#define P_COMBOI 1.0f
#define P_POWERCLEANPLUSCLEAN (0.9f * P_CLEANANDJERK)
#define P_POWERSNATCHPLUSSNATCH (0.9f * P_SNATCH)
#define P_POWERSNATCHPLUSTWOSNATCH (0.9f * P_SNATCH)
#define P_PUSHPRESS 1.1f // of press
#define P_FRONTSQUAT 1.224f // 0.875 of back squat value
#define P_SNATCHDROPS (1.05f * P_SNATCH)
#define P_SNATCHMUSCLE (0.85f * P_SNATCH)
#define P_SNATCHTHREEPARTS (0.8f * P_SNATCH)
#define P_SNATCHSHRUGS (1.0f * P_SNATCH)

#define P_CP 1.3f
#define P_CURL 0.5f
#define P_DEADLIFT 1.6f
#define P_DEADLIFTSNATCH 1.2f
#define P_DEADLIFTFINGER 0.32f
#define P_GOODMORNINGS 0.6f
#define P_INCLINEPRESS 0.9f
#define P_JBN 1.0f
#define P_JERKRACK 1.1f
#define P_JERKRECOVER 1.2f
#define P_JERKDIPS 1.0f
#define P_JERKPAUSE 0.9f
#define P_ONEARMROWS 0.4f
#define P_OVERHEADSQUATS 0.88f //(1.1f * P_SNATCH)
#define P_PRESS 0.75f // of cnj
#define P_PBN 1.1f // of press
#define P_PCANDPJ 0.95f
#define P_PPBN 1.2f // of press
#define P_POWERCLEAN 0.825f

#define P_POWERSNATCH (0.825f * P_SNATCH)

#define P_PULLUPS 10
#define P_PUSHUPS 25

#define P_RDL 1.6f
#define P_RDLBLOCKS 1.0
#define P_SHRUGSCG 1.2
#define P_SHRUGSSG 1.2

#define P_SNATCHKNESS (0.95 * P_SNATCH)
#define P_SNATCHPULL (1.3f  * P_SNATCH)


#define RUNNING_CONV_FT2MILES(x) x/5480.0f
#define RUNNING_CONV_FT2METERS(x) x*0.304801f
#define RUNNING_CONV_MILES2FT(x) (int)((float)x*5480.0f)
#define RUNNING_CONV_MILES2METERS(x) (int)((float)x*1609.344f)

#define s400MRUN (char *)"400m Run"
#define s4800MRUN (char *)"4800m Run"
#define sBENCHPRESS (char *)"Bench Press"
#define sBODYSQUATS (char *)"Body Squats"
#define sBURPEES (char *)"Burpees"
#define sCLEAN (char *)"Clean"
#define sCLEANANDJERK (char *)"Clean and Jerk"
#define sCLEANHIGHPULL (char *)"Clean High Pull"
#define sCLEANKNEES (char *)"Clean from knees"
#define sCLEANPULL (char *)"Clean Pull"
#define sCLEANTWOPARTS (char *) "2 Part Clean (Floor, Mid-thigh)"
#define sCLEANTHREEPARTS (char *) "3 Part Clean (Floor, Knee, Mid-thigh)"
#define sCLIMBING (char *)"Climbing"
#define sCOMBOA (char *)"Power Snatch + Snatch Recover + Overhead Squat"
#define sCOMBOB (char *)"Power Clean + Front Squat + Push Jerk"
#define sCOMBOC (char *)"Power Snatch + Overhead Squat"
#define sCOMBOD (char *)"KB Clean + Front Squat + Press + Overhead Squat"
#define sCOMBOE (char *)"Snatch + Push Jerk"
#define sCOMBOF (char *)"Power Clean + Front Squat + Jerk"
#define sCOMBOG (char *)"Freestyle Add-On"
#define sCOMBOH (char *)"Power Snatch + Overhead Squat + Push Press Behind Neck"
#define sCOMBOI (char *)"Snatch + 2 Drop Snatch + 3 Snatch Push Press + Hang Snatch"
#define sCROSSFIT (char *)"Crossfit"
#define sCROSSFIT_WOD (char *)"WOD"
#define sCRUNCH (char *)"Crunches"
#define sCURLS (char *)"Curls"
#define sDEADLIFT (char *)"Deadlift"
#define sDEADLIFTSNATCH (char *)"Deadlift (Snatch grip)"
#define sDEADLIFTFINGER (char *)"One Finger Deadlift"
#define sFREEMOTIONLEGCURLS (char *)"Free Motion Leg Curls"
#define sFRONTSQUAT (char *)"Front Squat"
#define sHYPERS (char *)"Hyper Extensions"
#define sGETUPSITUPS (char *)"Get up sit ups"
#define sGOODMORNINGS (char *)"Good Mornings"
#define sINCLINEPRESS (char *)"Incline Bench Press"
#define sISOSITUPS (char *)"Crunch with weight plus iso hold"
#define sJBN (char *)"Jerk Behind Neck"
#define sJERKDIPS (char *)"Jerk Dips"
#define sJERKPAUSE (char *)"Jerk Pause"
#define sJERKRACK (char *)"Jerk Rack"
#define sJERKRECOVER (char *)"Jerk Recover"
#define sJOB (char *)"Jump onto Box"
#define sJUMPROPE (char *)"Jump Rope"
#define sKETTLEBELLSWINGS (char *)"Kettlebell Swing"
#define sKETTLEBELLOHS (char *)"Kettlebell Overhead Squat"
#define sMANUALSITUPS (char *)"Manual Sit-ups"
#define sMEDICINEBALL (char *)"Medicine ball throw"
#define sONEARMROWS (char *)"One Arm Rows"
#define sOVERHEADSQUATS (char *)"Overhead Squat"
#define sPBN (char *)"Press Behind Neck"
#define sPCANDPJ (char *)"Power Clean + Push Jerk"
#define sPOWERCLEAN (char *)"Power Clean"
#define sPOWERSNATCH (char *)"Power Snatch"
#define sPOWERCLEANPLUSCLEAN (char *)"Power Clean + 2 Cleans"
#define sPOWERSNATCHPLUSSNATCH (char *)"Power Snatch + Snatch"
#define sPOWERSNATCHPLUSTWOSNATCH (char *)"Power Snatch + 2 Snatches"
#define sPPBN (char *)"Push Press Behind Neck"
#define sPRESS (char *)"Press"
#define sPUSHPRESS (char *)"Push Press"
#define sPUSHUPS (char *)"Push ups"
#define sPULLUPS (char *)"Pull ups"
#define sPULLUPSMAX (char *)"Pull ups (max)"
#define sRINGDIPS (char *)"Ring dips"
#define sRDL (char *)"Romanian Deadlifts"
#define sRDLBLOCKSAPOLLO (char *)"Romanian Deadlifts on blocks with Apollo bar"
#define sRUN (char *) "Run"
#define sSANDBAGSTAIRS (char *)"Sandbag stair run"
#define sSHRUGSCG (char *)"Shrugs Clean Grip"
#define sSHRUGSSG (char *)"Shrugs Snatch Grip"
#define sSITUPS (char *)"Sit-ups"
#define sSNATCH (char *)"Snatch"
#define sSNATCHKNEES (char *)"Snatch Knees"
#define sSNATCHPULL (char *)"Snatch Pull"
#define sSNATCHMUSCLE (char *)"Muscle Snatch"
#define sSNATCHSHRUGS (char *)"Snatch Shrugs"
#define sSNATCHTHREEPARTS (char *)"3 Part Snatch (Floor, Knee, Mid-thigh)"
#define sSQUAT (char *)"Back Squat"
#define sSAXONS (char *)"Saxons"
#define sSNATCHDROPS (char *)"Snatch Drop"
#define sSTOTTS (char *)"Stotts"
#define sTURKISHGETUPS (char *)"Turkish Getups"
#define sWALLBALLS (char *)"Wall balls"

typedef int ExerciseType;

#define CleanAndJerk          0
#define Snatch                1
#define Press                 2
#define BackSquat             3
#define Deadlift              4
#define FrontSquat            5
#define Clean                 6
#define CleanHighPull         7
#define CleanThreeParts       8
#define PowerClean            9
#define PowerCleanPlusClean   10
#define PowerSnatchPlusTwoSnatch 11
#define Running               12
#define Climbing              13
#define PPress                14
#define PBN                   15
#define PPBN                  16
#define CleanPull             17
#define SnatchDrop            18
#define SnatchPull            19
#define JerkRack              20
#define JerkDips              21
#define OverheadSquat         22
#define CombinationA          23
#define CombinationB          24
#define CombinationC          25
#define CombinationD          26
#define CombinationE          27
#define CombinationF          28
#define CombinationG          29
#define Crunches              30
#define SnatchMuscle          31
#define SnatchThreeParts      32
#define PowerSnatchPlusSnatch 33
#define CleanTwoParts         34
#define SnatchShrugs          35
#define JerkPause             36
#define SnatchPower           37
#define Pullups               38
#define Pushups							39
#define CombinationH          40
#define CombinationI          41
#define EndExerciseType       42

#define mCLIMBING_ROPE_OUTDOORS 1
#define mCLIMBING_ROPE_INDOORS 2
#define mCLIMBING_BOULDER_SPOT 4
#define mCLIMBING_BOULDER_OUTDOORS 8


#define mCLIMBING_5p2 9
#define mCLIMBING_5p3 12
#define mCLIMBING_5p4 15
#define mCLIMBING_5p5 18
#define mCLIMBING_5p6 21
#define mCLIMBING_5p7 24
#define mCLIMBING_5p8m 27
#define mCLIMBING_5p8 30
#define mCLIMBING_5p8p 33
#define mCLIMBING_5p9m 36
#define mCLIMBING_5p9 39
#define mCLIMBING_5p9p 42
#define mCLIMBING_5p10a 45
#define mCLIMBING_5p10b 48
#define mCLIMBING_5p10c 51
#define mCLIMBING_5p10d 54
#define mCLIMBING_5p11a 57
#define mCLIMBING_5p11b 60
#define mCLIMBING_5p11c 63
#define mCLIMBING_5p11d 66
#define mCLIMBING_5p12a 69
#define mCLIMBING_5p12b 72
#define mCLIMBING_5p12c 75
#define mCLIMBING_5p12d 78
#define mCLIMBING_5p13a 81
#define mCLIMBING_5p13b 84
#define mCLIMBING_5p13c 87
#define mCLIMBING_5p13d 90
#define mCLIMBING_5p14a 93
#define mCLIMBING_5p14b 96
#define mCLIMBING_5p14c 99
#define mCLIMBING_5p14d 100

#define mCLIMBING_V0 mCLIMBING_5p5
#define mCLIMBING_V0p mCLIMBING_5p6
#define mCLIMBING_V1 mCLIMBING_5p8
#define mCLIMBING_V2 mCLIMBING_5p9
#define mCLIMBING_V3 mCLIMBING_5p10a
#define mCLIMBING_V4 mCLIMBING_5p10d
#define mCLIMBING_V5 mCLIMBING_5p11b
#define mCLIMBING_V6 mCLIMBING_5p11d
#define mCLIMBING_V7 mCLIMBING_5p12a
#define mCLIMBING_V8 mCLIMBING_5p12c

#define mCLIMBING_SPOT1 mCLIMBING_V0
#define mCLIMBING_SPOT1p mCLIMBING_V1
#define mCLIMBING_SPOT2 mCLIMBING_V1
#define mCLIMBING_SPOT2p mCLIMBING_V2
#define mCLIMBING_SPOT3m mCLIMBING_V2
#define mCLIMBING_SPOT3 mCLIMBING_V3
#define mCLIMBING_SPOT3p mCLIMBING_V4
#define mCLIMBING_SPOT4m mCLIMBING_V5
#define mCLIMBING_SPOT4 mCLIMBING_V6
#define mCLIMBING_SPOT4p mCLIMBING_V7
#define mCLIMBING_SPOT5m mCLIMBING_V7
#define mCLIMBING_SPOT5 mCLIMBING_V8
#define mCLIMBING_SPOT5p mCLIMBING_V9

typedef int setType;

#define setxxx 0
#define set1x1 1
#define set1x5 2
#define set1x10 3
#define set1x20 4
#define set1x30 5
#define set1x40 6
#define set1x50 7
#define set1x60 8
#define set1x12 9
#define set1x100 10
#define set1x21159 11
#define set3x5 12
#define set5x3 13
#define set5x5 14
#define set5x5p80 15
#define set5x8 16
#define set5x8p80 17
#define set3x3 18
#define set3x3p80 19
#define set3x8 20
#define set3x10 21
#define set2x1 22
#define set2x5 23
#define set2x3 24
#define set853 25
#define set3x1 26
#define set4x1 27
#define set5x1 28
#define set6x1 29
#define set7x1 30
#define set8x1 31
#define set9x1 32
#define set10x1 33
#define set11x1 34
#define set12x1 35
#define set15x1 36
#define set20x1 37
#define set30x1 38
#define setTaper4x5533 39
#define setTaper4x7555 40
#define setTaper5x66655 41
#define setTaper5x77555 42
#define setTaper5x88666 43
#define setTaper6x3_1 44
#define setTaper7x6_4 45
#define setTime 46
#define set4x2 47
#define set4x5433 48
#define setTaper5x54433 49
#define setTaper4x4333 50
#define set6x4 51
#define set5x6 52
#define set5x7 53
#define setTaper6x211111 54
#define setTaper4x2211 55
#define set4x5 56
#define setTaper6x221111 57
#define set4x3 58
#define set6x5 59
#define setTaper6x332222 60
#define set7x4 61
#define set3x866 62


///////////////////////////////////////////////////////////////////////////

typedef float (*percentProc)(const int week, 
			     const int totalWeeks, 
			     int *pBase, 
			     int cycles, 
			     const void* ref);

float
percentSawtooth(const int week, 
		const int totalWeeks, 
		int *pBase, 
		int cycles, 
		const void* ref);

float
percentFlat(const int week, 
	    const int totalWeeks, 
	    int *pBase, 
	    int cycles, 
	    const void* ref);


///////////////////////////////////////////////////////////////////////////


const char * 
getClimbingGrade(int value, 
		 int climbingOption = mCLIMBING_ROPE_OUTDOORS);

///////////////////////////////////////////////////////////////////////////

// routine can be passed to check for arbitrary exercises that we want to
// match on.
typedef bool (*exerciseFilterProc)(const ExerciseType e);

bool filterCore(const ExerciseType e);

bool filterBodyWeight(const ExerciseType e);

bool filterOlympic(const ExerciseType e);

bool filterClimbing(const ExerciseType e);

bool filterRunning(const ExerciseType e);

bool filterPress(const ExerciseType e);

inline bool filterNothing(const ExerciseType e) { if (e) return false; return false; };

///////////////////////////////////////////////////////////////////////////

int WeightRound(int w, int round);

///////////////////////////////////////////////////////////////////////////

typedef int (*weightCalcProc)(const int steps, 
			      const int totalSteps, 
			      const int finishWeight,
			      const float basePercent,
			      const float slopeBasePercent,
			      float *pPercent);

int calcLinear(const int steps, 
	       const int totalSteps, 
	       const int finishWeight,
	       const float basePercent,
	       const float slopeBasePercent,
	       float *pPercent);

int calcFlat(const int steps, 
	     const int totalSteps, 
	     const int finishWeight,
	     const float basePercent,
	     const float slopeBasePercent,
	     float *pPercent);

int calcSine(const int steps, 
	     const int totalSteps, 
	     const int finishWeight,
	     const float basePercent,
	     const float slopeBasePercent,
	     float *pPercent);

int calcTriangle(const int steps, 
						 const int totalSteps, 
						 const int finishWeight,
						 const float basePercent,
						 const float slopeBasePercent,
						 float *pPercent);

int calcUnitStep(const int steps, 
								 const int totalSteps, 
								 const int finishWeight,
								 const float basePercent,
								 const float slopeBasePercent,
								 float *pPercent);

///////////////////////////////////////////////////////////////////////////


class Exercise {
public:
  Exercise(void);
  virtual ~Exercise(void) {};
  
  void AddSetType(ExerciseType e,
		  setType s, 
		  const int goalWeight, 
		  const int time,
		  const float basePercent,
		  weightCalcProc calcProc = calcFlat,
		  exerciseFilterProc exFilter = filterNothing,
		  float fSlopeBasePercent = 0.6f);	
  
  void AddSetTypeParams(const int sets,
			const int *reps,
			const int goalWeight,
			const int time,
			const float basePercent,
			weightCalcProc calcProc,
			float fSlopeBasePercent = 0.6f);
  
  // Access setting routines
  inline void SetType(ExerciseType e) { m_type = e; };
  inline void SetWeightMax(int w) { m_weightmax = w; };
  inline void SetTime(int sec) { m_time = sec; };
  inline void SetOptional(bool b) { m_optional = b; };
  inline void SetRatio(float p);
  
  // Access gathering routines
  inline ExerciseType GetType(void) { return m_type; };
  inline int GetWeightMax(void) { return m_weightmax; }
  inline int GetTime(void) { return m_time; };
  inline bool GetOptional(void) { return m_optional; };
  inline int GetNumberOfSets(void) { return m_nSets; };
  inline int GetNumberOfSetsConsolidated(void) { return m_nSetsConsolidated; };
  inline float GetRatio(void) { return m_fRatio; };
  const char * GetDescription(ExerciseType e = EndExerciseType);
  inline int GetSetWeight(int set) { 
    return m_setsConsolidated[set][EXERCISE_SETS_WEIGHT]; 
  };
  inline int GetSetReps(int set) { 
    return m_setsConsolidated[set][EXERCISE_SETS_REPS]; 
  };
  inline int GetSetRounds(int set) { 
    return m_setsConsolidated[set][EXERCISE_SETS_ROUNDS]; 
  };
  
  const char * GetAllSets(void);
  
private:
  

  
  ExerciseType m_type;
  int m_weightmax;
  int m_time;
  bool m_optional;
  int m_nSets;
  int m_nSetsConsolidated;
  int m_sets[EXERCISE_SETS_MAX][3];
  float m_fRatio;
  
  int m_setsConsolidated[EXERCISE_SETS_MAX][4];
  
};

////////////////////////////////////////////////////////////////////////////////

class ExerciseGoals : public Exercise {
public:	
  ExerciseGoals(void);
  ~ExerciseGoals(void) {};
  
  // Get and setting goal information
  bool ExerciseGoalSet(ExerciseType e, const int weight, const int time = 0);
  int ExerciseGoalGet(ExerciseType e, int *pWeight = NULL, int *pTime = NULL);
  inline float ExerciseGoalGetRatio(ExerciseType e) { return m_exercises[e].GetRatio(); };
  
  inline int ExerciseGoalGetAdjustment(ExerciseType e, float adjustedPercent, float basePercent) {
    return (int)(ExerciseGoalGet(e) * ((adjustedPercent * 1)));
  }
  
  bool ExerciseGoalsSetAll(void);
  
  const char * ExerciseGoalsShowAll(OutputType t, FILE *pFile = NULL);
  
private:
  // Total number of enumerated exercises we have to work with
  int m_nExercises;
  
  // All of our possible exercises
  Exercise m_exercises[EXERCISES_MAX];
  
};


#endif

